package com.tqz.zookeeper.lock;

import com.tqz.zookeeper.common.ZookeeperUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * 使用 curator 实现分布式锁.
 *
 * @author <a href="https://github.com/tian-qingzhao">tianqingzhao</a>
 * @since 2025/9/5 21:08
 */
@Slf4j
public class CuratorLockTest implements Runnable {

    private static final CuratorFramework CLIENT = CuratorFrameworkFactory.builder()
            .connectString(ZookeeperUtil.ZK_URL)
            .retryPolicy(new ExponentialBackoffRetry(100, 1, 5000))
            .build();

    // 可重入互斥锁
    private static final InterProcessMutex LOCK = new InterProcessMutex(CLIENT, "/curator_lock");

    private static int count = 0;

    public static void main(String[] args) throws InterruptedException {
        CLIENT.start();

        CountDownLatch latch = new CountDownLatch(30);

        for (int i = 0; i < 30; i++) {
            new Thread(() -> {
                new CuratorLockTest().run();
                latch.countDown();
            }).start();
        }

        // 等所有线程完成
        latch.await();
        CLIENT.close();
    }

    @Override
    public void run() {
        try {
            // 加锁
            LOCK.acquire();

            String orderCode = getOrderCode();
            log.info("生成订单号： {}", orderCode);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                LOCK.release();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public String getOrderCode() {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddhhmmss");
        return simpleDateFormat.format(new Date()) + "-" + ++count;
    }
}
